#ifndef WRAP_UNISTD_H
#define WRAP_UNISTD_H

#include <sys/types.h>

namespace Wrap {

const int STDIN_FIFENO_ = 0;
const int STDOUT_FILENO_ = 1;
const int STDERR_FILENO_ = 2;

int sc_clk_tck();
int sc_page_size();

/// @see https://man7.org/linux/man-pages/man2/close.2.html
/// @param fd close() closes a file descriptor @c fd, so that it no longer
/// refers to any file and may be reused.
/// @return close() returns zero on success. On error, -1 is returned, and
/// errno is set to indicate the error.
/// @throw EBADF @c fd isn't a valid open file descriptor.
/// @throw EINTR The close() call was interrupted by a signal; see signal(7).
/// @throw EIO An I/O error occurred.
/// @throw ENOSPC On NFS, these errors are not normally reported against the
/// first write which exceeds the available storage space, but instead against a
/// subsequent write(2), fsync(2), or close().
/// @throw EDQUOT see ENOSPC
int close_(int fd);

/// @see https://man7.org/linux/man-pages/man2/fork.2.html
/// @return On success, the PID of the child process is returned in the parent,
/// and 0 is returned in the child.  On failure, -1 is returned in the parent,
/// no child process is created, and errno is set to indicate the error.
/// @throw EAGAIN A system-imposed limit on the number of threads was
/// encountered.  There are a number of limits that may trigger this error: *
/// the RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits
/// the number of processes and threads for a real user ID, was reached; *  the
/// kernel's system-wide limit on the number of processes and threads,
/// /proc/sys/kernel/threads-max, was reached (see proc(5)); *  the maximum
/// number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)); or *
/// the PID limit (pids.max) imposed by the cgroup "process number" (PIDs)
/// controller was reached.
/// @throw EAGAIN The caller is operating under the SCHED_DEADLINE scheduling
/// policy and does not have the reset-on-fork flag set.  See sched(7).
/// @throw ENOMEM fork() failed to allocate the necessary kernel structures
/// because memory is tight.
/// @throw ENOMEM An attempt was made to create a child process in a PID
/// namespace whose "init" process has terminated.  See pid_namespaces(7).
/// @throw ENOSYS fork() is not supported on this platform (for example,
/// hardware without a Memory-Management Unit).
/// @throw ERESTARTNOINTR (since Linux 2.6.17) System call was interrupted by a
/// signal and will be restarted. (This can be seen only during a trace.)
pid_t fork_();

/// @see https://man7.org/linux/man-pages/man2/gethostname.2.html
/// @param name gethostname() returns the null-terminated hostname in the
/// character array @c name,
/// @param len which has a length of @c len bytes.
/// @return On success, zero is returned. On error, -1 is returned, and errno
/// is set to indicate the error.
/// @throw EFAULT @c name is an invalid address.
/// @throw EINVAL @c len is negative.
/// @throw ENAMETOOLONG (glibc gethostname()) @c len is smaller than the actual
/// size. (Before version 2.1, glibc uses EINVAL for this case.)
int gethostname_(char *name, size_t len);

/// @see https://man7.org/linux/man-pages/man2/geteuid.2.html
/// @brief geteuid() returns the effective user ID of the calling process.
uid_t geteuid_();

/// @see https://man7.org/linux/man-pages/man2/getpid.2.html
/// @brief getpid() returns the process ID (PID) of the calling process. (This
/// is often used by routines that generate unique temporary filenames.)
pid_t getpid_();

/// @see https://man7.org/linux/man-pages/man2/getppid.2.html
/// @brief getppid() returns the process ID of the parent of the calling
/// process. This will be either the ID of the process that created this
/// process using fork(), or, if that process has already terminated, the ID of
/// the process to which this process has been reparented (either init(1) or a
/// "subreaper" process defined via the prctl(2) PR_SET_CHILD_SUBREAPER
/// operation).
pid_t getppid_();

/// @see https://man7.org/linux/man-pages/man2/getuid.2.html
/// @brief getuid() returns the real user ID of the calling process.
uid_t getuid_();

/// @see https://man7.org/linux/man-pages/man2/pread.2.html
/// @param nbytes pread() reads up to @c nbytes bytes
/// @param fd from file descriptor @c fd
/// @param offset at offset @c offset (from the start of the file)
/// @param buf into the buffer starting at @c buf. The file offset is not
/// changed.
/// @return On success, pread() returns the number of bytes read (a return of
/// zero indicates end of file). Note that it is not an error for a successful
/// call to transfer fewer bytes than requested (see read(2) and write(2)). On
/// error, -1 is returned and errno is set to indicate the error.
/// @throw pread() can fail and set errno to any error specified for read(2) or
/// lseek(2).
ssize_t pread_(int fd, void *buf, size_t nbytes, off_t offset);

/// @see https://man7.org/linux/man-pages/man2/read.2.html
/// @param nbytes read() attempts to read up to @c nbytes bytes
/// @param fd from file descriptor @c fd
/// @param buf into the buffer starting at @c buf.
/// @return On success, the number of bytes read is returned (zero indicates
/// end of file), and the file position is advanced by this number. It is not
/// an error if this number is smaller than the number of bytes requested; this
/// may happen for example because fewer bytes are actually available right now
/// (maybe because we were close to end-of-file, or because we are reading from
/// a pipe, or from a terminal), or because read() was interrupted by a signal.
/// See also NOTES. On error, -1 is returned, and errno is set to indicate the
/// error. In this case, it is left unspecified whether the file position (if
/// any) changes.
/// @throw EAGAIN The file descriptor @c fd refers to a socket and has been
/// marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001
/// allows either error to be returned for this case, and does not require these
/// constants to have the same value, so a portable application should check for
/// both possibilities.
/// @throw EWOULDBLOCK see EAGAIN
/// @throw EAGAIN The file descriptor @c fd refers to a file other than a socket
/// and has been marked nonblocking (O_NONBLOCK), and the read would block.  See
/// open(2) for further details on the O_NONBLOCK flag.
/// @throw EBADF @c fd is not a valid file descriptor or is not open for
/// reading.
/// @throw EFAULT @c buf is outside your accessible address space.
/// @throw EINTR The call was interrupted by a signal before any data was read;
/// see signal(7).
/// @throw EINVAL @c fd is attached to an object which is unsuitable for
/// reading; or the file was opened with the O_DIRECT flag, and either the
/// address specified in @c buf, the value specified in @c nbytes, or the file
/// offset is not suitably aligned.
/// @throw EINVAL @c fd was created via a call to timerfd_create(2) and the
/// wrong size buffer was given to read(); see timerfd_create(2) for further
/// information.
/// @throw EIO I/O error.  This will happen for example when the process is in a
/// background process group, tries to read from its controlling terminal, and
/// either it is ignoring or blocking SIGTTIN or its process group is orphaned.
/// It may also occur when there is a low-level I/O error while reading from a
/// disk or tape.  A further possible cause of EIO on networked filesystems is
/// when an advisory lock had been taken out on the file descriptor and this
/// lock has been lost.  See the Lost locks section of fcntl(2) for further
/// details.
/// @throw EISDIR @c fd refers to a directory.
ssize_t read_(int fd, void *buf, size_t nbytes);

/// @see https://man7.org/linux/man-pages/man2/readlink.2.html
/// @param path readlink() places the contents of the symbolic link @c path
/// @param buf in the buffer @c buf,
/// @param len which has size @c len.
/// @return On success, these calls return the number of bytes placed in
/// @c buf. (If the returned value equals @c len, then truncation may have
/// occurred.)  On error, -1 is returned and errno is set to indicate the error.
/// @throw EACCES Search permission is denied for a component of the path
/// prefix.  (See also path_resolution(7).)
/// @throw EFAULT @c buf extends outside the process's allocated address space.
/// @throw EINVAL @c len is not positive.
/// @throw EINVAL The named file (i.e., the final filename component of @c path)
/// is not a symbolic link.
/// @throw EIO An I/O error occurred while reading from the filesystem.
/// @throw ELOOP Too many symbolic links were encountered in translating the
/// pathname.
/// @throw ENAMETOOLONG A pathname, or a component of a pathname, was too long.
/// @throw ENOENT The named file does not exist.
/// @throw ENOMEM Insufficient kernel memory was available.
/// @throw ENOTDIR A component of the path prefix is not a directory.
ssize_t readlink_(const char *path, char *buf, size_t len);

/// @see https://man7.org/linux/man-pages/man3/sleep.3.html
/// @param seconds sleep() causes the calling thread to sleep either until the
/// number of real-time seconds specified in @c seconds have elapsed or until a
/// signal arrives which is not ignored.
/// @return Zero if the requested time has elapsed, or the number of seconds
/// left to sleep, if the call was interrupted by a signal handler.
unsigned sleep_(unsigned seconds);

// @see https://man7.org/linux/man-pages/man2/syscall.2.html
/// @param sysno syscall() is a small library function that invokes the system
/// call whose assembly language interface has the specified @c sysno with the
/// specified arguments.
/// @return The return value is defined by the system call being invoked. In
/// general, a 0 return value indicates success. A -1 return value indicates an
/// error, and an error number is stored in errno.
long syscall_(long sysno, ...);

/// @see https://man7.org/linux/man-pages/man3/sysconf.3.html
/// @return On error, -1 is returned and errno is set to indicate the error
/// (for example, EINVAL, indicating that name is invalid).
/// @throw EINVAL @c name is invalid.
long sysconf_(int name);

/// @see https://man7.org/linux/man-pages/man2/write.2.html
/// @param n write() writes up to @c n bytes
/// @param buf from the buffer starting at @c buf
/// @param fd to the file referred to by the file descriptor @c fd.
/// @return On success, the number of bytes written is returned. On error, -1
/// is returned, and errno is set to indicate the error. Note that a successful
/// write() may transfer fewer than @c n bytes. Such partial writes can occur
/// for various reasons; for example, because there was insufficient space on
/// the disk device to write all of the requested bytes, or because a blocked
/// write() to a socket, pipe, or similar was interrupted by a signal handler
/// after it had transferred some, but before it had transferred all of the
/// requested bytes. In the event of a partial write, the caller can make
/// another write() call to transfer the remaining bytes. The subsequent call
/// will either transfer further bytes or may result in an error (e.g., if the
/// disk is now full). If @c n is zero and @c fd refers to a regular file, then
/// write() may return a failure status if one of the errors below is detected.
/// If no errors are detected, or error detection is not performed, 0 is
/// returned without causing any other effect. If @c n is zero and @c fd refers
/// to a file other than a regular file, the results are not specified.
/// @throw EAGAIN The file descriptor @c fd refers to a socket and has been
/// marked nonblocking (O_NONBLOCK), and the write would block. POSIX.1-2001
/// allows either error to be returned for this case, and does not require these
/// constants to have the same value, so a portable application should check for
/// both possibilities.
/// @throw EWOULDBLOCK see EAGAIN
/// @throw EAGAIN The file descriptor @c fd refers to a file other than a socket
/// and has been marked nonblocking (O_NONBLOCK), and the write would block. See
/// open(2) for further details on the O_NONBLOCK flag.
/// @throw EBADF @c fd is not a valid file descriptor or is not open for
/// writing.
/// @throw EDESTADDRREQ @c fd refers to a datagram socket for which a peer
/// address has not been set using connect(2).
/// @throw EDQUOT The user's quota of disk blocks on the filesystem containing
/// the file referred to by @c fd has been exhausted.
/// @throw EFAULT @c buf is outside your accessible address space.
/// @throw EFBIG  An attempt was made to write a file that exceeds the
/// implementation-defined maximum file size or the process's file size limit,
/// or to write at a position past the maximum allowed offset.
/// @throw EINTR The call was interrupted by a signal before any data was
/// written; see signal(7).
/// @throw EINVAL @c fd is attached to an object which is unsuitable for
/// writing; or the file was opened with the O_DIRECT flag, and either the
/// address specified in @c buf, the value specified in @c n, or the file offset
/// is not suitably aligned.
/// @throw EIO A low-level I/O error occurred while modifying the inode. This
/// error may relate to the write-back of data written by an earlier write(),
/// which may have been issued to a different file descriptor on the same file.
/// Since Linux 4.13, errors from write-back come with a promise that they may
/// be reported by subsequent.  write() requests, and will be reported by a
/// subsequent fsync(2) (whether or not they were also reported by write()).  An
/// alternate cause of EIO on networked filesystems is when an advisory lock had
/// been taken out on the file descriptor and this lock has been lost.  See the
/// Lost locks section of fcntl(2) for further details.
/// @throw ENOSPC The device containing the file referred to by @c fd has no
/// room for the data.
/// @throw EPERM The operation was prevented by a file seal; see fcntl(2).
/// @throw EPIPE @c fd is connected to a pipe or socket whose reading end is
/// closed.  When this happens the writing process will also receive a SIGPIPE
/// signal.  (Thus, the write return value is seen only if the program catches,
/// blocks or ignores this signal.)
ssize_t write_(int fd, const void *buf, size_t n);

}

#endif